﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Configuration;
using System.Data.EntityClient;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using DataLoader.Common;
using DataLoader.Common.Config;
using DataLoader.Config;
using DataLoader.UI.Commands;
using DataLoader.UI.Misc;
using DataLoader.UI.Models;
using DataLoader.UI.Services;


namespace DataLoader.UI.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        #region Events

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion


        #region Props

        public bool IsUserAdmin { get; set; }
        public string ConfigConnString { get; private set; }

        private string _UserName = String.Empty;
        public string UserName { get { return _UserName; } set { _UserName = value; OnPropertyChanged("UserName"); } }

        private bool _IsBusy;
        public bool IsBusy { get { return _IsBusy; } set { _IsBusy = value; OnPropertyChanged("IsBusy"); } }

        private bool _IsDirty;
        public bool IsDirty { get { return _IsDirty; } set { _IsDirty = value; OnPropertyChanged("IsDirty"); } }

        private string _StatusBarMessage = String.Empty;
        public string StatusBarMessage { get { return _StatusBarMessage; } set { _StatusBarMessage = value; OnPropertyChanged("StatusBarMessage"); } }

        private ObservableCollection<IConfigItem> _ConfigItems;
        public ObservableCollection<IConfigItem> ConfigItems
        {

            get { return _ConfigItems; }
            set { _ConfigItems = value; OnPropertyChanged("ConfigItems"); }
        }

        private ConfigSource _ConfigSource = ConfigSource.LOCAL;
        public ConfigSource ConfigSource
        {
            get { return _ConfigSource; }
            set
            {
                _ConfigSource = value;
                SetConfigSource();                
                OnPropertyChanged("ConfigSource");
            }
        }

        private void SetConfigSource()
        {
            if (_ConfigSource == ConfigSource.DEV) { ConfigConnString = ConfigurationManager.ConnectionStrings["ConfigEntities-DEV"].ConnectionString; }
            else { ConfigConnString = ConfigurationManager.ConnectionStrings["ConfigEntities"].ConnectionString; }
        }

        #endregion


        #region Commands

        public ICommand RefreshItemsCommand { get; set; }
        public ICommand UpdateItemsCommand { get; set; }

        #endregion


        public MainViewModel()
        {
            UserName = Environment.UserName;
            SetStatusWithMessage(false, string.Empty);

            RefreshItemsCommand = new RelayCommand(GetConfigItemsAsync, CanGetConfigItems);
            UpdateItemsCommand = new RelayCommand(UpdateConfigItemsAsync, CanGetConfigItems);

            ConfigItems = new ObservableCollection<IConfigItem>();
            SetUserAuthGroup();
        }


        private void SetUserAuthGroup()
        {
            bool isAdmin = new AuthService().IsInGroup(UserName, @"UK\SG. DWH - Developer Admin");
        }


        private void SetStatusWithMessage(bool isBusy, string message)
        {
            IsBusy = isBusy;
            StatusBarMessage = message;
        }


        private bool CanGetConfigItems(object obj)
        {
            if (IsBusy)
                return false;
            else
                return true;
        }


        private void GetConfigItemsAsync(object obj)
        {
            SetConfigSource();   
            SetStatusWithMessage(true, "Loading Config from Database...");

            try
            {
                MainModelService mainModelService = new MainModelService(ConfigConnString);
                IAsyncResult ar = mainModelService.BeginFetchConfigItems(null, new AsyncCallback(GetConfigItemsAsyncCallBack), mainModelService);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                SetStatusWithMessage(false, string.Empty);
            }
        }


        public void GetConfigItemsAsyncCallBack(IAsyncResult result)
        {
            if (((Task<List<IConfigItem>>)result).IsFaulted)
            {
                AggregateException aggEx = ((Task<List<IConfigItem>>)result).Exception.Flatten();
                FlattenedAggregateException flatAggEx = aggEx.HadleAggregateException();
                MessageBox.Show(flatAggEx.Message + Environment.NewLine + flatAggEx.StackTrace, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            else
            {
                MainModelService c = (MainModelService)result.AsyncState;
                List<IConfigItem> items = c.EndFetchConfigItems(result);
                ConfigItems = new ObservableCollection<IConfigItem>(items);
                IsDirty = false;
            }

            SetStatusWithMessage(false, "Data fetched from: " + GetDataSourceAndUserName() + ", User Status: " + (IsUserAdmin ? "[ADMIN]" : "[NON-ADMIN]" ));
        }

        private string GetDataSourceAndUserName()
        {
            string val = string.Empty;
            Regex regex = new Regex(Consts.REGEX_SQL_HOST);

            if (regex != null && regex.Match(ConfigConnString).Groups[1].Value != null)
                val = "[" + regex.Match(ConfigConnString).Groups[1].Value + "]";            
            
            return val;
        }


        private void UpdateConfigItemsAsync(object obj)
        {
            //Do checks and Update...
        }


        #region INotifyPropertyChanged Method

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
                handler(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }

}
